#ifndef __M__VIRTUALHOST_H_
#define __M__VIRTUALHOST_H_
#include "mq_exchange.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"
#include "mq_queue.hpp"

namespace mq
{
    // 虚拟机模块：整合交换机/队列/绑定/消息管理模块
    class VirtualHost
    {
    public:
        using ptr = shared_ptr<VirtualHost>;
        // 0.构造：各模块的初始化和历史数据恢复
        VirtualHost(const string &hostName, /*虚拟机名称*/ const string &basedir /*所有持久化存储数据存放目录*/, const string &dbfile /*数据库文件名*/)
            : _hostName(hostName),
              _dbfile(basedir + (basedir.back() == '/' ? "" : "/") + dbfile),
              _emp(make_shared<ExchangeManager>(_dbfile)),
              _qmp(make_shared<MsgQueueManager>(_dbfile)),
              _bmp(make_shared<BindingManager>(_dbfile)),
              _mmp(make_shared<MessageManager>(basedir))
        {
            // 交换机/队列/绑定都根据数据库文件里对应的表，在构造时自动数据恢复
            // 消息的数据恢复：获取所有队列名称，恢复队列历史消息
            MsgQueueMap qmap = _qmp->allQueue();
            for (auto &it : qmap)
            {
                _mmp->initQueueMessage(it.first);
            }
        }
        // 1.交换机的声明/删除
        bool declareExchange(const string &name, ExchangeType type, bool durable, bool auto_delete, Map &args)
        {
            return _emp->declareExchange(name, type, durable, auto_delete, args);
        }
        void deleteExchange(const string &name)
        {
            // 删除交换机，需要把交换机相关的绑定也删掉
            _bmp->removeExchangeBindings(name);
            _emp->deleteExchange(name);
        }
        // 2.队列的声明/删除
        bool declareMsgQueue(const string &name, bool exclusive, bool durable, bool auto_delete, Map &args)
        {
            // 队列对象的声明和队列消息的创建
            _mmp->initQueueMessage(name);
            return _qmp->declareMsgQueue(name, exclusive, durable, auto_delete, args);
        }
        void deleteMsgQueue(const string &name)
        {
            // 队列删除时，需要把队列相关的绑定和队列消息也删除
            _bmp->removeMsgQueueBindings(name);
            _mmp->destroyQueueMessage(name);
            _qmp->deleteMsgQueue(name);
        }
        // 3.绑定/解绑
        bool Bind(const string &ename, const string &qname, const string &binding_key)
        {
            ex_ptr exchange = _emp->selectExchange(ename);
            q_ptr queue = _qmp->selectMsgQueue(qname);
            if (exchange == ex_ptr())
            {
                DLOG("绑定失败，该交换机不存在： %s", ename.c_str());
                return false;
            }
            if (queue == q_ptr())
            {
                DLOG("绑定失败，该队列不存在： %s", qname.c_str());
                return false;
            }
            bool durable = exchange->_durable && queue->_durable; // 只有当交换机和队列同时持久化，绑定才有持久化的必要

            return _bmp->Bind(ename, qname, binding_key, durable);
        }
        void unBind(const string &ename, const string &qname)
        {
            if (!_emp->exists(ename))
            {
                DLOG("解绑失败，该交换机不存在： %s", ename.c_str());
                return;
            }
            if (!_qmp->exists(qname))
            {
                DLOG("解绑失败，该队列不存在： %s", qname.c_str());
                return;
            }
            _bmp->unBind(ename, qname);
        }
        // 4.获取交换机绑定的所有队列
        MsgQueueBindingMap getExchangeBindings(const string &ename)
        {
            if (!_emp->exists(ename))
            {
                DLOG("获取交换机绑定队列失败，该交换机不存在： %s", ename.c_str());
                return MsgQueueBindingMap();
            }
            return _bmp->getExchangeBindings(ename);
        }
        // 5.发布消息/获取消息/确认消息
        bool basicPublish(const string &qname, const BasicProperties *bp, const string &body)
        {
            q_ptr queue = _qmp->selectMsgQueue(qname);
            if (queue == q_ptr())
            {
                DLOG("发布消息失败，该队列不存在：%s", qname.c_str());
                return false;
            }
            return _mmp->insert(qname, bp, body, queue->_durable);
        }
        m_ptr basicConsume(const string &qname)
        {
            if (!_qmp->exists(qname))
            {
                DLOG("获取消息失败，该队列不存在：%s", qname.c_str());
                return m_ptr();
            }
            m_ptr msgp = _mmp->front(qname);
            if (msgp == m_ptr())
                DLOG("获取消息失败，该队列可推送消息数量为0：%s", qname.c_str());
            return msgp;
        }
        void basicAck(const string &qname, const string &msg_id)
        {
            if (!_qmp->exists(qname))
            {
                DLOG("确认消息失败，该队列不存在：%s ack %s", msg_id.c_str(), qname.c_str());
                return;
            }
            _mmp->ack(qname, msg_id);
        }
        void clear()
        {
            _emp->clear(); // 删除交换机数据表
            _qmp->clear(); // 删除队列数据表
            _bmp->clear(); // 删除绑定数据表
            FileHelper fh(_dbfile);
            fh.removeFile(); // 删除数据库文件
            _mmp->clear();   // 删除所有队列数据文件
        }

        Exchange::ptr selectExchange(const string &ename) // 获取指定交换机
        {
            return _emp->selectExchange(ename);
        }
        MsgQueueMap allQueues() // 获取所有队列
        {
            return _qmp->allQueue();
        }
        bool existExchange(const string &ename) // 判断交换机是否存在
        {
            return _emp->selectExchange(ename) != ex_ptr();
        }
        bool existMsgQueue(const string &qname) // 判断队列机是否存在
        {
            return _qmp->selectMsgQueue(qname) != q_ptr();
        }
        bool existBinding(const string &ename, const string &qname) // 判断队列机是否存在
        {
            return _bmp->exist_test(ename, qname);
        }

    private:
        const string _hostName;
        const string _dbfile;
        ExchangeManager::manager_ptr _emp;
        MsgQueueManager::manager_ptr _qmp;
        BindingManager::manager_ptr _bmp;
        MessageManager::manager_ptr _mmp;
    };
}
#endif